home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / EnhancedMesh / EnhancedMesh.cs next >
Encoding:
Text File  |  2004-09-28  |  33.1 KB  |  713 lines

  1. //-----------------------------------------------------------------------------
  2. // File: EnhancedMesh.cs
  3. //
  4. // Enhance mesh sample
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9.  
  10. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  11. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  12.  
  13. using System;
  14. using Microsoft.DirectX;
  15. using Microsoft.DirectX.Direct3D;
  16. using Microsoft.Samples.DirectX.UtilityToolkit;
  17.  
  18. namespace EnhancedMeshSample
  19. {
  20.     /// <summary>EnhancedMesh Sample Class</summary>
  21.     public class EnhancedMesh : IFrameworkCallback, IDeviceCreation
  22.     {
  23.         #region Creation
  24.         /// <summary>Create a new instance of the class</summary>
  25.         public EnhancedMesh(Framework f) 
  26.         { 
  27.             // Store framework
  28.             sampleFramework = f; 
  29.             // Create dialogs
  30.             hud = new Dialog(sampleFramework); 
  31.             sampleUi = new Dialog(sampleFramework); 
  32.         }
  33.         #endregion
  34.  
  35.         // Variables
  36.         private Framework sampleFramework = null; // Framework for samples
  37.         private Font statsFont = null; // Font for drawing text
  38.         private Sprite textSprite = null; // Sprite for batching text calls
  39.         private Effect effect = null; // D3DX Effect Interface
  40.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  41.         private bool isHelpShowing = true; // If true, renders the UI help text
  42.         private Dialog hud = null; // dialog for standard controls
  43.         private Dialog sampleUi = null; // dialog for sample specific controls
  44.  
  45.         // Sample specific variables
  46.         private Mesh systemMemoryMesh = null; // system memory version of mesh, lives through resize's
  47.         private Mesh vidMemEnhancedMesh = null; // vid mem version of mesh that is enhanced
  48.         private int numberSegments = 2; // number of segments per edge (tesselation level)
  49.         private Material[] meshMaterials = null; // array of materials
  50.         private Texture[] meshTextures = null; // array of textures, entries are null if no texture specified
  51.         private Vector3 objectCenter; // Center of bounding sphere of object
  52.         private float objectRadius; // Radius of bounding sphere of object
  53.         private Matrix worldCenter; // World matrix to center the mesh
  54.         private GraphicsStream adjacencyBuffer = null; // Contains the adjacency info loaded with the mesh
  55.         private Texture defaultTexture = null; // Default white texture
  56.         private bool isUsingHardwarePatches = true;
  57.         private bool isWireframe = false;
  58.  
  59.         // HUD Ui Control constants
  60.         private const int ToggleFullscreen = 1;
  61.         private const int ToggleReference = 3;
  62.         private const int ChangeDevice = 4;
  63.         private const int FillModeButton = 5;
  64.         private const int SegmentLabel = 6;
  65.         private const int SegmentSlider = 7;
  66.         private const int HwPatchButton = 8;
  67.  
  68.         /// <summary>
  69.         /// Called during device initialization, this code checks the device for some 
  70.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  71.         /// </summary>
  72.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  73.         {
  74.             // No fallback defined by this app, so reject any device that 
  75.             // doesn't support at least ps1.1
  76.             if (caps.PixelShaderVersion < new Version(1,1))
  77.                 return false;
  78.  
  79.             // Skip back buffer formats that don't support alpha blending
  80.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  81.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  82.                 return false;
  83.  
  84.             return true;
  85.         }
  86.  
  87.         /// <summary>
  88.         /// This callback function is called immediately before a device is created to allow the 
  89.         /// application to modify the device settings. The supplied settings parameter 
  90.         /// contains the settings that the framework has selected for the new device, and the 
  91.         /// application can make any desired changes directly to this structure.  Note however that 
  92.         /// the sample framework will not correct invalid device settings so care must be taken 
  93.         /// to return valid device settings, otherwise creating the Device will fail.  
  94.         /// </summary>
  95.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  96.         {
  97.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  98.             // then switch to SWVP.
  99.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  100.                 (caps.VertexShaderVersion < new Version(1,1)) )
  101.             {
  102.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  103.             }
  104.             else
  105.             {
  106.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  107.             }
  108.  
  109.             // This application is designed to work on a pure device by not using 
  110.             // any get methods, so create a pure device if supported and using HWVP.
  111.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  112.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  113.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  114.  
  115.             // Debugging vertex shaders requires either REF or software vertex processing 
  116.             // and debugging pixel shaders requires REF.  
  117. #if(DEBUG_VS)
  118.             if (settings.DeviceType != DeviceType.Reference )
  119.             {
  120.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  121.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  122.             }
  123. #endif
  124. #if(DEBUG_PS)
  125.             settings.DeviceType = DeviceType.Reference;
  126. #endif
  127.  
  128.         }
  129.  
  130.         /// <summary>
  131.         /// This event will be fired immediately after the Direct3D device has been 
  132.         /// created, which will happen during application initialization and windowed/full screen 
  133.         /// toggles. This is the best location to create Pool.Managed resources since these 
  134.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  135.         /// here should be released in the Disposing event. 
  136.         /// </summary>
  137.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  138.         {
  139.             // See if there is hardware support for N-Patches
  140.             if (!e.Device.DeviceCaps.DeviceCaps.SupportsNPatches)
  141.             {
  142.                 // No hardware support.  Disable the checkbox
  143.                 isUsingHardwarePatches = false;
  144.                 sampleUi.GetCheckbox(HwPatchButton).IsChecked = false;
  145.                 sampleUi.GetCheckbox(HwPatchButton).IsEnabled = false;
  146.             }
  147.             else
  148.             {
  149.                 sampleUi.GetCheckbox(HwPatchButton).IsEnabled = true;
  150.             }
  151.  
  152.             // Initialize the stats font
  153.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  154.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  155.                 , "Arial");
  156.  
  157.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  158.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  159.             // processing, and debugging pixel shaders requires REF.  The 
  160.             // ShaderFlags.Force*SoftwareNoOptimizations flag improves the debug experience in the 
  161.             // shader debugger.  It enables source level debugging, prevents instruction 
  162.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  163.             // against the next higher available software target, which ensures that the 
  164.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  165.             // flags will cause slower rendering since the shaders will be unoptimized and 
  166.             // forced into software.  See the DirectX documentation for more information about 
  167.             // using the shader debugger.
  168.             ShaderFlags shaderFlags = ShaderFlags.None;
  169. #if(DEBUG_VS)
  170.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  171. #endif
  172. #if(DEBUG_PS)
  173.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  174. #endif
  175.             // Read the D3DX effect file
  176.             string path = Utility.FindMediaFile("EnhancedMesh.fx");
  177.             effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  178.                 path, null, null, shaderFlags, null);
  179.  
  180.             // Load the mesh
  181.             ExtendedMaterial[] materials;
  182.             path = Utility.FindMediaFile("dwarf\\dwarf.x");
  183.             
  184.             // Change the current directory to the mesh's directory so we can
  185.             // find the textures.
  186.             string currentFolder = System.IO.Directory.GetCurrentDirectory();
  187.             System.IO.FileInfo info = new System.IO.FileInfo(path);
  188.             System.IO.Directory.SetCurrentDirectory(info.Directory.FullName);
  189.  
  190.             systemMemoryMesh = Mesh.FromFile(path, MeshFlags.SystemMemory,
  191.                 e.Device, out adjacencyBuffer, out materials);
  192.  
  193.             // Find the mesh's center, then generate a centering matrix
  194.             using(VertexBuffer vb = systemMemoryMesh.VertexBuffer)
  195.             {
  196.                 using (GraphicsStream stm = vb.Lock(0, 0, LockFlags.NoSystemLock))
  197.                 {
  198.                     try
  199.                     {
  200.                         objectRadius = Geometry.ComputeBoundingSphere(stm,
  201.                             systemMemoryMesh.NumberVertices, systemMemoryMesh.VertexFormat, out objectCenter);
  202.  
  203.                         worldCenter = Matrix.Translation(-objectCenter);
  204.                     }
  205.                     finally
  206.                     {
  207.                         vb.Unlock();
  208.                     }
  209.                 }
  210.             }
  211.  
  212.             // Allocate a material/texture arrays
  213.             meshMaterials = new Material[materials.Length];
  214.             meshTextures = new Texture[materials.Length];
  215.  
  216.             // Copy the materials and load the textures
  217.             for(int i = 0; i < meshMaterials.Length; i++)
  218.             {
  219.                 meshMaterials[i] = materials[i].Material3D;
  220.                 meshMaterials[i].AmbientColor = meshMaterials[i].DiffuseColor;
  221.  
  222.                 if ( (materials[i].TextureFilename != null) && (materials[i].TextureFilename.Length > 0) )
  223.                 {
  224.                     // Create the texture
  225.                     meshTextures[i] = ResourceCache.GetGlobalInstance().CreateTextureFromFile(e.Device, materials[i].TextureFilename);
  226.                 }
  227.             }
  228.  
  229.             // Make sure there are normals, which are required for the tesselation
  230.             // enhancement.
  231.             if ((systemMemoryMesh.VertexFormat & VertexFormats.Normal) == 0)
  232.             {
  233.                 Mesh temporaryMesh = systemMemoryMesh.Clone(systemMemoryMesh.Options.Value,
  234.                     systemMemoryMesh.VertexFormat | VertexFormats.Normal, e.Device);
  235.  
  236.                 // Compute normals now
  237.                 temporaryMesh.ComputeNormals();
  238.  
  239.                 // Set the mesh
  240.                 systemMemoryMesh.Dispose();
  241.                 systemMemoryMesh = temporaryMesh;
  242.             }
  243.  
  244.             // Restore the original folder
  245.             System.IO.Directory.SetCurrentDirectory(currentFolder);
  246.  
  247.             // Create the 1x1 white default texture
  248.             defaultTexture = new Texture(e.Device, 1, 1, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
  249.             using (GraphicsStream data = defaultTexture.LockRectangle(0, LockFlags.None))
  250.             {
  251.                 // Write a single white pixel
  252.                 data.Write(0xffffffff);
  253.                 // Now unlock
  254.                 defaultTexture.UnlockRectangle(0);
  255.             }
  256.  
  257.             // Setup the camera's view parameters
  258.             camera.SetViewParameters(new Vector3(0.0f, 0.0f, -5.0f), Vector3.Empty);
  259.         }
  260.         
  261.         /// <summary>
  262.         /// This event will be fired immediately after the Direct3D device has been 
  263.         /// reset, which will happen after a lost device scenario. This is the best location to 
  264.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  265.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  266.         /// event. 
  267.         /// </summary>
  268.         private void OnResetDevice(object sender, DeviceEventArgs e)
  269.         {
  270.             SurfaceDescription desc = e.BackBufferDescription;
  271.             // Create a sprite to help batch calls when drawing many lines of text
  272.             textSprite = new Sprite(e.Device);
  273.  
  274.             // Generate the enhanced mesh
  275.             GenerateEnhancedMesh(e.Device, numberSegments);
  276.  
  277.             // Set the fill mode
  278.             if (isWireframe)
  279.                 e.Device.RenderState.FillMode = FillMode.WireFrame;
  280.             else
  281.                 e.Device.RenderState.FillMode = FillMode.Solid;
  282.  
  283.             // Setup the camera's projection parameters
  284.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  285.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 1000.0f);
  286.             camera.SetWindow(desc.Width, desc.Height);
  287.  
  288.             // Setup UI locations
  289.             hud.SetLocation(desc.Width-170, 0);
  290.             hud.SetSize(170,170);
  291.             sampleUi.SetLocation(desc.Width - 170, desc.Height - 350);
  292.             sampleUi.SetSize(170,300);
  293.         }
  294.  
  295.         /// <summary>
  296.         /// This event function will be called fired after the Direct3D device has 
  297.         /// entered a lost state and before Device.Reset() is called. Resources created
  298.         /// in the OnResetDevice callback should be released here, which generally includes all 
  299.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  300.         /// information about lost devices.
  301.         /// </summary>
  302.         private void OnLostDevice(object sender, EventArgs e)
  303.         {
  304.             if (textSprite != null)
  305.             {
  306.                 textSprite.Dispose();
  307.                 textSprite = null;
  308.             }
  309.             if (vidMemEnhancedMesh != null)
  310.             {
  311.                 vidMemEnhancedMesh.Dispose();
  312.                 vidMemEnhancedMesh = null;
  313.             }
  314.         }
  315.  
  316.         /// <summary>
  317.         /// This callback function will be called immediately after the Direct3D device has 
  318.         /// been destroyed, which generally happens as a result of application termination or 
  319.         /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  320.         /// should be released here, which generally includes all Pool.Managed resources. 
  321.         /// </summary>
  322.         private void OnDestroyDevice(object sender, EventArgs e)
  323.         {
  324.             meshTextures = null;
  325.             meshMaterials = null;
  326.  
  327.             if (systemMemoryMesh != null)
  328.             {
  329.                 systemMemoryMesh.Dispose();
  330.                 systemMemoryMesh = null;
  331.             }
  332.             if (adjacencyBuffer != null)
  333.             {
  334.                 adjacencyBuffer.Dispose();
  335.                 adjacencyBuffer = null;
  336.             }
  337.  
  338.             if (defaultTexture != null)
  339.             {
  340.                 defaultTexture.Dispose();
  341.                 defaultTexture = null;
  342.             }
  343.         }
  344.  
  345.         /// <summary>
  346.         /// This callback function will be called once at the beginning of every frame. This is the
  347.         /// best location for your application to handle updates to the scene, but is not 
  348.         /// intended to contain actual rendering calls, which should instead be placed in the 
  349.         /// OnFrameRender callback.  
  350.         /// </summary>
  351.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  352.         {
  353.             // Update the camera's position based on user input 
  354.             camera.FrameMove(elapsedTime);
  355.  
  356.             // Set device transforms
  357.             device.Transform.World = camera.WorldMatrix;
  358.             device.Transform.View = camera.ViewMatrix;
  359.         }
  360.  
  361.         /// <summary>
  362.         /// This callback function will be called at the end of every frame to perform all the 
  363.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  364.         /// repainted. After this function has returned, the sample framework will call 
  365.         /// Device.Present to display the contents of the next buffer in the swap chain
  366.         /// </summary>
  367.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  368.         {
  369.             bool beginSceneCalled = false;
  370.  
  371.             // Clear the render target and the zbuffer 
  372.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x00424B79, 1.0f, 0);
  373.             try
  374.             {
  375.                 device.BeginScene();
  376.                 beginSceneCalled = true;
  377.  
  378.                 // Update the effect's variables.  Instead of using strings, it would 
  379.                 // be more efficient to cache a handle to the parameter by calling 
  380.                 // Effect.GetParameter
  381.                 effect.SetValue("g_mWorldViewProjection", worldCenter * camera.WorldMatrix * camera.ViewMatrix * camera.ProjectionMatrix);
  382.                 effect.SetValue("g_mWorld", camera.WorldMatrix);
  383.                 effect.SetValue("g_fTime", (float)appTime);
  384.  
  385.                 if (isUsingHardwarePatches)
  386.                 {
  387.                     device.NPatchMode = (float)numberSegments;
  388.                 }
  389.  
  390.                 int passes = effect.Begin(0);
  391.                 for(int pass = 0; pass < passes; pass++)
  392.                 {
  393.                     effect.BeginPass(pass);
  394.                     // Set and draw each of the materials in the mesh
  395.                     for (int i = 0; i < meshMaterials.Length; i++)
  396.                     {
  397.                         effect.SetValue("g_vDiffuse", meshMaterials[i].DiffuseColor);
  398.                         if (meshTextures[i] != null)
  399.                             effect.SetValue("g_txScene", meshTextures[i]);
  400.                         else
  401.                             effect.SetValue("g_txScene", defaultTexture);
  402.  
  403.                         // Since we're setting values between the BeginPass/EndPass calls, we 
  404.                         // must call CommitChanges before the call to draw
  405.                         effect.CommitChanges();
  406.                         vidMemEnhancedMesh.DrawSubset(i);
  407.                     }
  408.                     effect.EndPass();
  409.                 }
  410.                 effect.End();
  411.  
  412.                 if (isUsingHardwarePatches)
  413.                 {
  414.                     device.NPatchMode = 0.0f;
  415.                 }
  416.  
  417.                 // Show frame rate
  418.                 RenderText();
  419.  
  420.                 // Show UI
  421.                 hud.OnRender(elapsedTime);
  422.                 sampleUi.OnRender(elapsedTime);
  423.             }
  424.             finally
  425.             {
  426.                 if (beginSceneCalled)
  427.                     device.EndScene();
  428.             }
  429.         }
  430.  
  431.         /// <summary>
  432.         /// Render the help and statistics text. This function uses the Font object for 
  433.         /// efficient text rendering.
  434.         /// </summary>
  435.         private void RenderText()
  436.         {
  437.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  438.  
  439.             // Output statistics
  440.             txtHelper.Begin();
  441.             txtHelper.SetInsertionPoint(5,5);
  442.             txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
  443.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  444.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  445.  
  446.             // Draw help
  447.             if (isHelpShowing)
  448.             {
  449.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  450.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  451.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  452.  
  453.                 txtHelper.SetInsertionPoint(40, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  454.                 txtHelper.DrawTextLine("Rotate mesh: Left click drag");
  455.                 txtHelper.DrawTextLine("Rotate camera: right click drag");
  456.                 txtHelper.DrawTextLine("Zoom: mouse wheel");
  457.                 txtHelper.DrawTextLine("Quit: Esc");
  458.                 txtHelper.DrawTextLine("Hide help: F1");
  459.             }
  460.             else
  461.             {
  462.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*2);
  463.                 txtHelper.SetForegroundColor(System.Drawing.Color.White);
  464.                 txtHelper.DrawTextLine("Press F1 for help");
  465.             }
  466.  
  467.             txtHelper.SetInsertionPoint(10, 65);
  468.             txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  469.             txtHelper.DrawTextLine("Number Segments: {0}\n", numberSegments);
  470.             txtHelper.DrawTextLine("Number Faces: {0}\n", (vidMemEnhancedMesh == null) ? 0 : vidMemEnhancedMesh.NumberFaces);
  471.             txtHelper.DrawTextLine("Number Vertices: {0}\n", (vidMemEnhancedMesh == null) ? 0 : vidMemEnhancedMesh.NumberVertices);
  472.  
  473.             txtHelper.End();
  474.         }
  475.  
  476.         /// <summary>
  477.         /// As a convenience, the sample framework inspects the incoming windows messages for
  478.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  479.         /// messages to the application.  The framework does not remove the underlying keystroke 
  480.         /// messages, which are still passed to the application's MsgProc callback.
  481.         /// </summary>
  482.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  483.         {
  484.             if (isKeyDown)
  485.             {
  486.                 switch(key)
  487.                 {
  488.                     case System.Windows.Forms.Keys.F1:
  489.                         isHelpShowing = !isHelpShowing;
  490.                         break;
  491.                 }
  492.             }
  493.         }
  494.  
  495.         /// <summary>
  496.         /// Before handling window messages, the sample framework passes incoming windows 
  497.         /// messages to the application through this callback function. If the application sets 
  498.         /// noFurtherProcessing to true, the sample framework will not process the message
  499.         /// </summary>
  500.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  501.         {
  502.             // Give the dialog a chance to handle the message first
  503.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  504.             if (noFurtherProcessing)
  505.                 return IntPtr.Zero;
  506.  
  507.             noFurtherProcessing = sampleUi.MessageProc(hWnd, msg, wParam, lParam);
  508.             if (noFurtherProcessing)
  509.                 return IntPtr.Zero;
  510.  
  511.             // Pass all remaining windows messages to camera so it can respond to user input
  512.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  513.  
  514.             return IntPtr.Zero;
  515.         }
  516.  
  517.         /// <summary>
  518.         /// Initializes the application
  519.         /// </summary>
  520.         public void InitializeApplication()
  521.         {
  522.             int y = 10;
  523.             // Initialize the HUD
  524.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  525.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  526.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  527.             // Hook the button events for when these items are clicked
  528.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  529.             toggleRef.Click += new EventHandler(OnRefClicked);
  530.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  531.  
  532.             // Now add the sample specific UI
  533.             y = 10;
  534.             Checkbox fillModeBox = sampleUi.AddCheckBox(FillModeButton, "WireFrame (F8)", 35, y, 150, 20, false,
  535.                 System.Windows.Forms.Keys.F8, false);
  536.             sampleUi.AddStatic(SegmentLabel, "Number of segments: 2", 10, y += 30, 150, 16);
  537.             Slider segmentSlider = sampleUi.AddSlider(SegmentSlider, 10, y += 14, 150, 24, 1, 10, 2, false);
  538.             Checkbox hwPatch = sampleUi.AddCheckBox(HwPatchButton, "User hardware N-patches", 10, y += 26, 150, 20, true, 
  539.                 System.Windows.Forms.Keys.H, false);
  540.  
  541.             // Hook the events
  542.             fillModeBox.Changed += new EventHandler(OnFillmodeChanged);
  543.             segmentSlider.ValueChanged += new EventHandler(OnSegmentChanged);
  544.             hwPatch.Changed += new EventHandler(OnHardwareChanged);
  545.         }
  546.  
  547.         /// <summary>Called when the change device button is clicked</summary>
  548.         private void OnChangeDevicClicked(object sender, EventArgs e)
  549.         {
  550.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  551.         }
  552.  
  553.         /// <summary>Called when the full screen button is clicked</summary>
  554.         private void OnFullscreenClicked(object sender, EventArgs e)
  555.         {
  556.             sampleFramework.ToggleFullscreen();
  557.         }
  558.  
  559.         /// <summary>Called when the ref button is clicked</summary>
  560.         private void OnRefClicked(object sender, EventArgs e)
  561.         {
  562.             sampleFramework.ToggleReference();
  563.         }
  564.  
  565.         /// <summary>Fired when the fill mode box is changed</summary>
  566.         private void OnFillmodeChanged(object sender, EventArgs e)
  567.         {
  568.             isWireframe = (sender as Checkbox).IsChecked;
  569.             sampleFramework.Device.RenderState.FillMode = isWireframe ? FillMode.WireFrame : FillMode.Solid;
  570.         }
  571.  
  572.         /// <summary>Fired when the number of segments has changed</summary>
  573.         private void OnSegmentChanged(object sender, EventArgs e)
  574.         {
  575.             numberSegments = (sender as Slider).Value;
  576.             sampleUi.GetStaticText(SegmentLabel).SetText(string.Format("Number of segments: {0}", numberSegments));
  577.             GenerateEnhancedMesh(sampleFramework.Device, numberSegments);
  578.         }
  579.  
  580.         /// <summary>Fired when the N-Patch hardware box is changed</summary>
  581.         private void OnHardwareChanged(object sender, EventArgs e)
  582.         {
  583.             isUsingHardwarePatches = (sender as Checkbox).IsChecked;
  584.             GenerateEnhancedMesh(sampleFramework.Device, numberSegments);
  585.         }
  586.  
  587.         /// <summary>Generate a mesh that can be tesselated.</summary>
  588.         private void GenerateEnhancedMesh(Device device, int newNumberSegs)
  589.         {
  590.             Mesh meshEnhancedSysMem = null;
  591.             Mesh meshTemp = null;
  592.  
  593.             if (systemMemoryMesh == null)
  594.                 return;
  595.  
  596.             // if using hw, just copy the mesh
  597.             if (isUsingHardwarePatches)
  598.             {
  599.                 meshTemp = systemMemoryMesh.Clone(MeshFlags.WriteOnly | MeshFlags.NPatches | 
  600.                     (systemMemoryMesh.Options.Value & MeshFlags.Use32Bit), 
  601.                     systemMemoryMesh.VertexFormat, device);
  602.             }
  603.             else  // tesselate the mesh in sw
  604.             {
  605.                 try
  606.                 {
  607.                     // Create an enhanced version of the mesh, will be in sysmem since source is
  608.                     meshEnhancedSysMem = Mesh.TessellateNPatches(systemMemoryMesh, adjacencyBuffer, 
  609.                         newNumberSegs, false);
  610.                 }
  611.                 catch
  612.                 {
  613.                     // If the tessellate failed, there might have been more triangles or vertices 
  614.                     // than can fit into a 16bit mesh, so try cloning to 32bit before tessellation
  615.                     using(meshTemp = systemMemoryMesh.Clone(MeshFlags.SystemMemory | MeshFlags.Use32Bit, systemMemoryMesh.VertexFormat, device))
  616.                     {
  617.                         meshEnhancedSysMem = Mesh.TessellateNPatches(meshTemp, adjacencyBuffer, newNumberSegs, false);
  618.                     }
  619.                 }
  620.  
  621.                 using (meshEnhancedSysMem)
  622.                 {
  623.                     // Make a video memory version of the mesh  
  624.                     // Only set WriteOnly if it doesn't use 32bit indices, because those 
  625.                     // often need to be emulated, which means that D3DX needs read-access.
  626.                     MeshFlags meshEnhancedFlags = meshEnhancedSysMem.Options.Value & MeshFlags.Use32Bit;
  627.                     if ((meshEnhancedFlags & MeshFlags.Use32Bit) == 0)
  628.                         meshEnhancedFlags |= MeshFlags.WriteOnly;
  629.  
  630.                     meshTemp = meshEnhancedSysMem.Clone(meshEnhancedFlags, systemMemoryMesh.VertexFormat, device);
  631.                 }
  632.             }
  633.  
  634.             // Cleanup enhanced mesh if already exists
  635.             if (vidMemEnhancedMesh != null)
  636.                 vidMemEnhancedMesh.Dispose();
  637.  
  638.             vidMemEnhancedMesh = meshTemp;
  639.             numberSegments = newNumberSegs;
  640.         }
  641.  
  642.         /// <summary>
  643.         /// Entry point to the program. Initializes everything and goes into a message processing 
  644.         /// loop. Idle time is used to render the scene.
  645.         /// </summary>
  646.         static int Main() 
  647.         {
  648.             using(Framework sampleFramework = new Framework())
  649.             {
  650.                 EnhancedMesh sample = new EnhancedMesh(sampleFramework);
  651.                 // Set the callback functions. These functions allow the sample framework to notify
  652.                 // the application about device changes, user input, and windows messages.  The 
  653.                 // callbacks are optional so you need only set callbacks for events you're interested 
  654.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  655.                 // framework won't be able to reset your device since the application must first 
  656.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  657.                 // device created/destroyed callbacks then the sample framework won't be able to 
  658.                 // recreate your device resources.
  659.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  660.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  661.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  662.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  663.  
  664.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  665.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  666.  
  667.                 sampleFramework.SetCallbackInterface(sample);
  668.                 try
  669.                 {
  670.  
  671.                     // Show the cursor and clip it when in full screen
  672.                     sampleFramework.SetCursorSettings(true, true);
  673.  
  674.                     // Initialize
  675.                     sample.InitializeApplication();
  676.  
  677.                     // Initialize the sample framework and create the desired window and Direct3D 
  678.                     // device for the application. Calling each of these functions is optional, but they
  679.                     // allow you to set several options which control the behavior of the sampleFramework.
  680.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  681.                     sampleFramework.CreateWindow("Enhanced Mesh - N-Patches");
  682.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  683.                         sample);
  684.  
  685.                     // Pass control to the sample framework for handling the message pump and 
  686.                     // dispatching render calls. The sample framework will call your FrameMove 
  687.                     // and FrameRender callback when there is idle time between handling window messages.
  688.                     sampleFramework.MainLoop();
  689.  
  690.                 }
  691. #if(DEBUG)
  692.                 catch (Exception e)
  693.                 {
  694.                     // In debug mode show this error (maybe - depending on settings)
  695.                     sampleFramework.DisplayErrorMessage(e);
  696. #else
  697.             catch
  698.             {
  699.                 // In release mode fail silently
  700. #endif
  701.                     // Ignore any exceptions here, they would have been handled by other areas
  702.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  703.                 }
  704.  
  705.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  706.                 // appropriate callback functions and therefore don't require any cleanup code here.
  707.                 return sampleFramework.ExitCode;
  708.             }
  709.         }
  710.  
  711.     }
  712. }
  713.